/*
 * Copyright:  2018 smarabbit studio.
 *
 *  Licensed under the Confluent Community License; you may not use this file
 *  except in compliance with the License.  You may obtain a copy of the License at
 *
 *  http://www.confluent.io/confluent-community-license
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 *  WARRANTIES OF ANY KIND, either express or implied.  See the License for the
 *  specific language governing permissions and limitations under the License.
 *
 *  @作   者： 黄开晖 (117227773@qq.com)
 *  @日   期:  2021年10月5日
 */
package com.massyframework.beanskin.guice.beancontext;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.Module;
import com.massyframework.beanskin.ModuleListener;
import com.massyframework.beanskin.assembly.Assembly;
import com.massyframework.beanskin.assembly.AssemblyContextAware;
import com.massyframework.beanskin.assembly.AssemblyContextDelegate;
import com.massyframework.beanskin.assembly.handling.ActivationHandler;
import com.massyframework.beanskin.assembly.handling.HandlerBase;
import com.massyframework.beanskin.assembly.handling.HandlerRegistration;
import com.massyframework.beanskin.assembly.handling.LifecycleEventAdapter;
import com.massyframework.beanskin.service.ServiceRepository;


/**
 * 提供封装Guice的BeanContext的实现。
 */
public class GuiceHandler extends HandlerBase
        implements ActivationHandler {

    private volatile HandlerRegistration<AssemblyContextDelegate<GuiceBeanContextAdapter>> registration;
    private EventListener listener;
    private Set<Object> beans;

    public GuiceHandler(){
        this.beans = new HashSet<> ();
    }

    /**
     * 启动,使得进入激活状态
     *
     * @throws Exception 启动时发生非预期例外
     */
    @Override
    public synchronized void doStarting() throws Exception {
        if (registration == null){
            this.listener = new EventListener();
            this.getLifecycleManager().addListener(this.listener);

            this.registration = this.createAndRegistAssemblyContext();
        }
    }

    /**
     * 已停止，退出激活状态
     *
     * @throws Exception 停止时发生非预期例外
     */
    @Override
    public synchronized void doStopped() throws Exception {
        if (this.registration != null){
            this.unregisterAssemblyContext();

            this.getLifecycleManager().removeListener(this.listener);
            this.listener = null;
        }
    }


    /**
     * 创建并注册装配件上下文
     * @return {@link HandlerRegistration}
     */
    protected HandlerRegistration<AssemblyContextDelegate<GuiceBeanContextAdapter>> createAndRegistAssemblyContext()
            throws Exception {
        Injector injector = this.createInjector();
        GuiceBeanContextAdapter beanContext = this.createBeanContext(injector);
        AssemblyContextDelegate<GuiceBeanContextAdapter> assemblyContext = this.createAssemblyContext(beanContext);
        return this.getLifecycleManager().register(assemblyContext);
    }

    /**
     * 创建{@link AssemblyContextDelegate}
     * @param beanContext {@link GuiceBeanContextAdapter}
     * @return {@link AssemblyContextDelegate}
     */
    protected AssemblyContextDelegate<GuiceBeanContextAdapter> createAssemblyContext(GuiceBeanContextAdapter beanContext){
        return new AssemblyContextDelegate<>(beanContext);
    }

    /**
     * 创建{@link GuiceBeanContextAdapter}
     * @param injector {@link Injector}
     * @return {@link GuiceBeanContextAdapter}
     */
    protected GuiceBeanContextAdapter createBeanContext(Injector injector) throws Exception{
        return new GuiceBeanContextAdapter(injector);
    }

    /**
     * 创建Injector
     * @return {@link Injector}
     */
    protected Injector createInjector() throws Exception{
        DependencyModule module = new DependencyModule(this.getLifecycleManager());
        Module[] modules = this.getModules(module);
        return Guice.createInjector(modules);
    }

    /**
     * 获取模块集合
     * @param module 模块
     * @return {@link Module}数组
     * @throws ClassNotFoundException
     * @throws IllegalAccessException
     * @throws InstantiationException
     */
    protected Module[] getModules(Module module) throws Exception{
        Class<?>[] classes = this.getAssociatedAssembly()
        		.getConfig().getConfigTypes();

        List<Module> result = new ArrayList<Module>();
        result.add(module);
        for (Class<?> clazz: classes){
            module = (Module)clazz.newInstance();
            result.add(module);
        }
        return result.toArray(new Module[result.size()]);
    }

    /**
     * 绑定
     */
    protected synchronized void onBind(){
        AssemblyContextDelegate<GuiceBeanContextAdapter> context =
                this.registration.getHandler();
        Assembly assembly = context.getAssociatedAssembly();

        //注册监听器
        Map<String, ModuleListener> listenerMap = context.getBeansOfType(ModuleListener.class);
        for (Map.Entry<String, ModuleListener> entry: listenerMap.entrySet()){
        	ModuleListener bean = entry.getValue();
            assembly.addListener(bean);
            this.beans.add(bean);
        }

        //AssemblyContext 注入
        Map<String, AssemblyContextAware> contextAwareMap = context.getBeansOfType(AssemblyContextAware.class);
        for (Map.Entry<String, AssemblyContextAware> entry: contextAwareMap.entrySet()){
            AssemblyContextAware bean = entry.getValue();
            bean.setAssemblyContext(context);
            this.beans.add(bean);
        }
    }

    protected synchronized void onUnbind(){
        Set<Object> beans = new HashSet<>(this.beans);
        this.beans.clear();

        Assembly assembly = this.getAssociatedAssembly();
        for (Object bean: beans){
            AssemblyContextAware.tryToBind(bean, null);
            if (ModuleListener.class.isAssignableFrom(bean.getClass())){
                assembly.removeListener((ModuleListener)bean);
            }
        }
    }

    /**
     * 取消装配件上下文注册
     */
    protected void unregisterAssemblyContext() {
        this.registration.unregister();
        this.registration = null;
    }

    /**
     * 根据<code>assembly</code>获取{@link ServiceRepository}
     * @param assembly {@link Assembly}, 装配件
     * @return {@link ServiceRepository}
     */
    protected ServiceRepository getServiceRepository(Assembly assembly){
        return ServiceRepository.retrieveFrom(assembly);
    }

    private class EventListener extends LifecycleEventAdapter {
        /**
         * 已激活，装配件进入工作状态
         */
        @Override
        public void onActivated() {
            super.onActivated();
            onBind();
        }

        /**
         * 正在钝化，装配件准备退出工作状态
         */
        @Override
        public void onInactivating() {
            onUnbind();
            super.onInactivating();
        }
    }
}
